[XENBUS] Introduce new "online" node for backend drivers.
authorkaf24@firebug.cl.cam.ac.uk <kaf24@firebug.cl.cam.ac.uk>
Thu, 31 Aug 2006 23:33:19 +0000 (00:33 +0100)
committerkaf24@firebug.cl.cam.ac.uk <kaf24@firebug.cl.cam.ac.uk>
Thu, 31 Aug 2006 23:33:19 +0000 (00:33 +0100)
Driver changes:  Make backend drivers check it when entering Closed
state, only unregister devices when the "online" node is either "0" or
not present.  The later maintains backward compatibility.

Tools changes:  Update "online" node when creating and hot-unplugging
devices.

Background: When kexec'ing a new kernel, the old kernel's frontend
driver will shutdown, but the backend device should *NOT* disappear
due to that, so the new kernel instance can reconnect.

Signed-off-by: Gerd Hoffmann <kraxel@suse.de>
linux-2.6-xen-sparse/drivers/xen/blkback/xenbus.c
linux-2.6-xen-sparse/drivers/xen/blktap/common.h
linux-2.6-xen-sparse/drivers/xen/blktap/interface.c
linux-2.6-xen-sparse/drivers/xen/blktap/xenbus.c
linux-2.6-xen-sparse/drivers/xen/netback/xenbus.c
linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_backend_client.c
linux-2.6-xen-sparse/include/xen/xenbus.h
tools/python/xen/xend/server/DevController.py

index 931f7bf4bc447310c7f233127109c37680180284..02f90a68039233c6a31d5a8eca13f4f9736a5a5f 100644 (file)
@@ -301,11 +301,11 @@ static void frontend_changed(struct xenbus_device *dev,
        struct backend_info *be = dev->dev.driver_data;
        int err;
 
-       DPRINTK("");
+       DPRINTK("%s", xenbus_strstate(frontend_state));
 
        switch (frontend_state) {
        case XenbusStateInitialising:
-               if (dev->state == XenbusStateClosing) {
+               if (dev->state == XenbusStateClosed) {
                        printk("%s: %s: prepare for reconnect\n",
                               __FUNCTION__, dev->nodename);
                        xenbus_switch_state(dev, XenbusStateInitWait);
@@ -331,8 +331,12 @@ static void frontend_changed(struct xenbus_device *dev,
                xenbus_switch_state(dev, XenbusStateClosing);
                break;
 
-       case XenbusStateUnknown:
        case XenbusStateClosed:
+               xenbus_switch_state(dev, XenbusStateClosed);
+               if (xenbus_dev_is_online(dev))
+                       break;
+               /* fall through if not online */
+       case XenbusStateUnknown:
                device_unregister(&dev->dev);
                break;
 
index e610bed9e4f662d06811770e6f322836479a2fe7..56faca7a606aa2e2803ffb88ab57f3bca1221ea6 100644 (file)
@@ -91,6 +91,7 @@ blkif_t *tap_alloc_blkif(domid_t domid);
 void tap_blkif_free(blkif_t *blkif);
 int tap_blkif_map(blkif_t *blkif, unsigned long shared_page, 
                  unsigned int evtchn);
+void tap_blkif_unmap(blkif_t *blkif);
 
 #define blkif_get(_b) (atomic_inc(&(_b)->refcnt))
 #define blkif_put(_b)                                  \
index 19e0eda0a0438f52b571e0e7ffc4c6f13337045d..b0eccf4225747f3607677b75a44268b07ab62737 100644 (file)
@@ -135,20 +135,25 @@ int tap_blkif_map(blkif_t *blkif, unsigned long shared_page,
        return 0;
 }
 
-void tap_blkif_free(blkif_t *blkif)
+void tap_blkif_unmap(blkif_t *blkif)
 {
-       atomic_dec(&blkif->refcnt);
-       wait_event(blkif->waiting_to_free, atomic_read(&blkif->refcnt) == 0);
-
-       /* Already disconnected? */
-       if (blkif->irq)
+       if (blkif->irq) {
                unbind_from_irqhandler(blkif->irq, blkif);
-
+               blkif->irq = 0;
+       }
        if (blkif->blk_ring.sring) {
                unmap_frontend_page(blkif);
                free_vm_area(blkif->blk_ring_area);
+               blkif->blk_ring.sring = NULL;
        }
+}
+
+void tap_blkif_free(blkif_t *blkif)
+{
+       atomic_dec(&blkif->refcnt);
+       wait_event(blkif->waiting_to_free, atomic_read(&blkif->refcnt) == 0);
 
+       tap_blkif_unmap(blkif);
        kmem_cache_free(blkif_cachep, blkif);
 }
 
index e0158592cf0d483e4a3812e75acde7c7e726d64a..6c16a2e60bfcfba376dbea0dbfefaa4631a1d6fa 100644 (file)
@@ -247,6 +247,11 @@ static void tap_frontend_changed(struct xenbus_device *dev,
 
        switch (frontend_state) {
        case XenbusStateInitialising:
+               if (dev->state == XenbusStateClosed) {
+                       printk("%s: %s: prepare for reconnect\n",
+                              __FUNCTION__, dev->nodename);
+                       xenbus_switch_state(dev, XenbusStateInitWait);
+               }
                break;
 
        case XenbusStateInitialised:
@@ -264,11 +269,20 @@ static void tap_frontend_changed(struct xenbus_device *dev,
                break;
 
        case XenbusStateClosing:
+               if (be->blkif->xenblkd) {
+                       kthread_stop(be->blkif->xenblkd);
+                       be->blkif->xenblkd = NULL;
+               }
+               tap_blkif_unmap(be->blkif);
                xenbus_switch_state(dev, XenbusStateClosing);
                break;
 
-       case XenbusStateUnknown:
        case XenbusStateClosed:
+               xenbus_switch_state(dev, XenbusStateClosed);
+               if (xenbus_dev_is_online(dev))
+                       break;
+               /* fall through if not online */
+       case XenbusStateUnknown:
                device_unregister(&dev->dev);
                break;
 
index 9da8e3b4be8d25ffde7cc304052cffdbc9485fc4..a8b19a65be62e00abb704bb57d60758dfa1dff2a 100644 (file)
@@ -228,13 +228,13 @@ static void frontend_changed(struct xenbus_device *dev,
 {
        struct backend_info *be = dev->dev.driver_data;
 
-       DPRINTK("");
+       DPRINTK("%s", xenbus_strstate(frontend_state));
 
        be->frontend_state = frontend_state;
 
        switch (frontend_state) {
        case XenbusStateInitialising:
-               if (dev->state == XenbusStateClosing) {
+               if (dev->state == XenbusStateClosed) {
                        printk("%s: %s: prepare for reconnect\n",
                               __FUNCTION__, dev->nodename);
                        if (be->netif) {
@@ -260,8 +260,12 @@ static void frontend_changed(struct xenbus_device *dev,
                xenbus_switch_state(dev, XenbusStateClosing);
                break;
 
-       case XenbusStateUnknown:
        case XenbusStateClosed:
+               xenbus_switch_state(dev, XenbusStateClosed);
+               if (xenbus_dev_is_online(dev))
+                       break;
+               /* fall through if not online */
+       case XenbusStateUnknown:
                if (be->netif != NULL)
                        kobject_uevent(&dev->dev.kobj, KOBJ_OFFLINE);
                device_unregister(&dev->dev);
index b99991cdabcf11c4352d042f9d57f5736b9dd808..cd8ba02383ddda5eafdd187ebea6f6f7787a2dff 100644 (file)
@@ -132,4 +132,16 @@ int xenbus_unmap_ring(struct xenbus_device *dev,
 }
 EXPORT_SYMBOL_GPL(xenbus_unmap_ring);
 
+int xenbus_dev_is_online(struct xenbus_device *dev)
+{
+       int rc, val;
+
+       rc = xenbus_scanf(XBT_NIL, dev->nodename, "online", "%d", &val);
+       if (rc != 1)
+               val = 0; /* no online node present */
+
+       return val;
+}
+EXPORT_SYMBOL_GPL(xenbus_dev_is_online);
+
 MODULE_LICENSE("Dual BSD/GPL");
index 993f317b7cafaf94b38ba7404e132f1f20b5c104..cd09eb89855940c8cdbab4d9b5aa689118533c7f 100644 (file)
@@ -298,5 +298,6 @@ void xenbus_dev_fatal(struct xenbus_device *dev, int err, const char *fmt,
 int __init xenbus_dev_init(void);
 
 char *xenbus_strstate(enum xenbus_state state);
+int xenbus_dev_is_online(struct xenbus_device *dev);
 
 #endif /* _XEN_XENBUS_H */
index 92e298c9df7eed7ce164b91ee9f855d5abcf7680..e90008dbc0d245bf880d94c769c9773bfa78a964 100644 (file)
@@ -207,6 +207,9 @@ class DevController:
 
         devid = int(devid)
 
+        # Modify online status /before/ updating state (latter is watched by
+        # drivers, so this ordering avoids a race).
+        self.writeBackend(devid, 'online', "0")
         self.writeBackend(devid, 'state', str(xenbusState['Closing']))
 
 
@@ -406,7 +409,8 @@ class DevController:
             'domain' : self.vm.getName(),
             'frontend' : frontpath,
             'frontend-id' : "%i" % self.vm.getDomid(),
-            'state' : str(xenbusState['Initialising'])
+            'state' : str(xenbusState['Initialising']),
+            'online' : "1"
             })
 
         return (backpath, frontpath)